﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;

using Moe.ECamel.Common.Entities;

namespace Moe.ECamel.Server.BL
{
	/// <summary>
	/// Business Logic component for Libraries.
	/// </summary>
	public class LibraryBL : ECamelBL
	{
		/// <summary>
		/// Default constructor for business logic component.
		/// </summary>
		/// <param name="dataContext">Data context to be used by this component's operations.</param>
		public LibraryBL(ECamelDataContext dataContext)
			: base(dataContext)
		{
		}

		/// <summary>
		/// Gets a list of all the libraries.
		/// </summary>
		/// <returns>A list of all libraries.</returns>
		public List<Library> GetAllLibraries()
		{
			// Configure load options:
			DataLoadOptions loadOptions = new DataLoadOptions();
			loadOptions.LoadWith<Library>(l => l.LibraryType);
			ECamelDataContext adhocDC = new ECamelDataContext(dataContext.Connection);
			adhocDC.ObjectTrackingEnabled = false;
			adhocDC.LoadOptions = loadOptions;
			// Get libraries:
			List<Library> libraries = (from l in adhocDC.Libraries
									   orderby l.LibraryId
									  select l
									  ).ToList();
			// Get parent libraries:
			var extraInfo = (from l in adhocDC.Libraries
							 orderby l.LibraryId
							 select new { l.ParentLibrary.LibraryName }).ToList();
			for (int i = 0; i < libraries.Count; i++)
			{
				libraries[i].ParentLibraryName = extraInfo[i].LibraryName;
			}

			return libraries;
		}
		/// <summary>
		/// Create a new library.
		/// </summary>
		/// <param name="library">Details of new library.</param>
		/// <returns>If valid null, otherwise - a validation error.</returns>
		public ECamelError CreateLibrary(Library library)
		{
			// Validate:
			ECamelError validationError = ValidateLibrary(library);
			if (validationError != null)
				return validationError;

			// Add library to libraries table:
			dataContext.Libraries.InsertOnSubmit(library);
			AttachRelatedEntities(library);
			// Return with no error:
			return null;
		}
		/// <summary>
		/// Updates a library.
		/// </summary>
		/// <param name="library">Details of updated library.</param>
		/// <returns>If valid null, otherwise - a validation error.</returns>
		public ECamelError UpdateLibrary(Library library)
		{
			// Validate library:
			ECamelError validationError = ValidateLibrary(library);
			if (validationError != null)
				return validationError;

			// Update library:
			dataContext.Libraries.Attach(library, true);

			// Return with no error:
			return null;
		}

		/// <summary>
		/// Validates a library.
		/// </summary>
		/// <param name="library">Library to validate.</param>
		/// <returns>If valid - null, otherwise the validation error.</returns>
		private ECamelError ValidateLibrary(Library library)
		{
			// Validate library:
			ECamelError error = library.Validate();
			if (error != null)
				return error;

			// Validate library name is unique:
			int others = (from l in dataContext.Libraries
						  where l.LibraryName == library.LibraryName && l.LibraryId != library.LibraryId
						  select l.LibraryId).Count();
			if (others > 0)
				return new ECamelError(MessageIds.LibraryInvalidDuplicateName);

			// No validation errors:
			return null;
		}

		/// <summary>
		/// Prepares a library to be re-attached.
		/// </summary>
		/// <param name="library">Library to be attached.</param>
		private void AttachRelatedEntities(Library library)
		{
			// Re-attach library type:
			if (library.LibraryType != null)
				dataContext.LibraryTypes.Attach(library.LibraryType);
			// Re-attach parent library, if any:
			if (library.ParentLibrary != null)
			{
				dataContext.Libraries.Attach(library.ParentLibrary);
				dataContext.LibraryTypes.Attach(library.ParentLibrary.LibraryType);
			}
		}

		public Library GetLibraryById(int libraryId)
		{
			var library = (from l in dataContext.Libraries where l.LibraryId == libraryId select l).SingleOrDefault();
			return library;
		}
	}
}